import socket
import time
import asyncio
from collections import deque
from fastapiApp.controllers.agvs_control import AGV_car_controller
from fastapiApp.models.agvs import *
from fastapiApp.schemas.agvs_scheams import *
import os
import socket

# 使用统一的日志配置
from fastapiApp.setting.logger_config import get_udp_logger
logger = get_udp_logger()

async def async_udp_clients():
    """创建并运行多个异步UDP客户端"""
    clients = []

    # 读取AGV_car  UDP 配置
    query = await AGV_car_Mo.filter(isenable=1)
    agv_car_list = [
        await role.to_dict()
        for role in query
    ]

    for agv in agv_car_list:
        client = SimpleUDPClient(agv['remote_host'], agv['remote_port'], agv['local_port'],
                                 agv['timeout']/1000, agv['timesend']/1000, agv['agv_index'])
        clients.append(client)

    # 创建client 并加入task
    tasks = [client.start() for client in clients]

    try:
        # 等待所有任务完成
        await asyncio.gather(*tasks)
    except asyncio.CancelledError:
        logger.info("UDP客户端任务被取消")
    except Exception as e:
        logger.error(f"UDP客户端运行错误: {e}")
    finally:
        # 停止所有客户端
        for client in clients:
            client.stop()


class SimpleUDPClient:
    def __init__(self, remote_host, remote_port, local_port, timeout, timesend, car_index):
        self.remote_host = remote_host
        self.remote_port = remote_port
        self.local_port = local_port
        self.timeout = timeout  # 响应超时时间(秒)
        self.timesend = timesend  # 发送间隔时间
        self.car_index = car_index
        self.sock = None
        self.pending_requests = deque(maxlen=10)  # 保留最近10个待响应请求
        self.is_running = False

    async def start(self):
        """启动异步 UDP 客户端"""
        # 创建 UDP socket
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.sock.setblocking(False)

        try:
            # 绑定到指定端口
            self.sock.bind(('0.0.0.0', self.local_port))
            print(f"UDP 客户端已启动,本地端口: {self.local_port}")
        except OSError:
            self.sock.bind(('0.0.0.0', 0))
            self.local_port = self.sock.getsockname()[1]
            logger.info(f"UDP 端口占用,更改本地端口: {self.local_port}")

        print(f"目标服务器: {self.remote_host}:{self.remote_port}")

        self.is_running = True

        # 创建发送和接收任务
        send_task = asyncio.create_task(self.send_loop())
        receive_task = asyncio.create_task(self.receive_loop())
        timeout_task = asyncio.create_task(self.timeout_checker_loop())

        try:
            # 等待任务完成
            await asyncio.gather(send_task, receive_task, timeout_task)
        except asyncio.CancelledError:
            logger.warning(
                f"port:{self.remote_port}-errorcode:E0003 - 任务异常 程序异常退出")
        finally:
            self.stop()

    async def send_loop(self):
        """定时发送数据的循环"""
        while self.is_running:
            try:
                # 生成假数据 写入数据库
                # 生成环境删除
                await creat_data(self.car_index)

                # 获取数据 数组
                agv_realdata = await AGV_realdata_Mo.filter(car_index=self.car_index, type="W").first()
                db_data = agv_realdata.data
                str_data = db_data.replace('0x', '')
                str_data = str_data.replace(',', '')
                byte_data = bytes.fromhex(str_data)  # 转换为字节类型

                # 发送数据
                loop = asyncio.get_event_loop()
                await loop.sock_sendto(self.sock, byte_data, (self.remote_host, self.remote_port))
                logger.info(f"port:{self.remote_port}-已发送:")

                # 记录待响应请求
                self.pending_requests.append({
                    'send_time': time.time(),  # 创建消息并记录发送时间
                    'data': str_data
                })

                # 等待指定时间
                await asyncio.sleep(self.timesend)

            except Exception as e:
                logger.warning(
                    f"port:{self.remote_port}-errorcode:E004 - 发送数据时发生错误,{e}")
                await asyncio.sleep(1)  # 出错时等待一秒再继续

    async def receive_loop(self):
        """接收响应的循环"""
        loop = asyncio.get_event_loop()
        while self.is_running:
            try:
                # 接收数据
                data, addr = await loop.sock_recvfrom(self.sock, 1024)

                # 处理响应
                await self.process_response(data, addr)

            except asyncio.CancelledError:
                break
            except Exception as e:
                logger.warning(
                    f"port:{self.remote_port}-errorcode:E005 - 接收数据时发生错误: {e}")
                await asyncio.sleep(0.1)  # 出错时短暂等待

    async def process_response(self, data: bytes, addr: tuple):
        """处理接收到的响应"""
        str_data = ',0x'.join([f'{b:02X}' for b in data])
        str_data = '0x' + str_data

        agv_realdata = await AGV_realdata_Mo.filter(car_index=self.car_index, type="R").first()
        agv_realdata.data = str_data
        agv_realdata.status = 'ok'
        await agv_realdata.save()

        # response_text = data.decode('utf-8')

        # 查找匹配的请求
        for i, request in enumerate(self.pending_requests):
            # 简单检查响应是否包含请求的时间戳
            # if str(request['send_time']) in response_text:
            if 1:
                rtt = (time.time() - request['send_time']) * 1000  # 转换为毫秒
                logger.info(
                    f"port:{self.remote_port}-收到响应: {str_data}, RTT: {rtt:.2f}ms")
                # 从待处理请求中移除
                if i < len(self.pending_requests):
                    self.pending_requests.remove(request)
                return

        logger.info(f"port:{self.remote_port}-收到未知响应: {str_data} 来自 {addr}")

    async def timeout_checker_loop(self):
        """创建超时检查任务"""
        while self.is_running:
            try:
                await self.check_timeouts()
                await asyncio.sleep(0.5)  # 每0.5秒检查一次超时
            except Exception as e:
                logger.warning(
                    f"port:{self.remote_port}-errorcode:E006 - 检查任务发生错误,{e}")
                await asyncio.sleep(0.5)  # 出错时等待一秒再继续

    async def check_timeouts(self):
        """检查超时的请求"""
        current_time = time.time()
        timed_out = []

        for request in self.pending_requests:
            if current_time - request['send_time'] > self.timeout:
                agv = await AGV_realdata_Mo.filter(car_index=self.car_index, type="R").first()
                agv.data = None
                agv.status = 'timeout'
                await agv.save()
                timed_out.append(request)
                logger.info(
                    f"port:{self.remote_port}-请求超时: 发送时间 {request['send_time']}")

        # 移除超时的请求
        for request in timed_out:
            if request in self.pending_requests:
                self.pending_requests.remove(request)

    def stop(self):
        """停止客户端"""
        self.is_running = False
        if self.sock:
            self.sock.close()
        logger.info(f"port:{self.remote_port}-UDP 客户端已停止")

# 生成校验码 并写入数据库  临时数据
async def creat_data(car_index):
    agv_realdata = await AGV_realdata_Mo.filter(car_index=car_index, type="W").first()

    dats = [0x2C, 0x00, 0xFD, 0xFC, 0xFB, 0xFA, 0x00,
            0x2C, 0x2C, 0x00, 0xEF, 0x01, 0x01, 0xAA, 0xAA]
    dats.append(agv_realdata.car_index)

    for i in range(16, 45):
        dats.append(i + agv_realdata.car_index)

    sumdata = 0x00
    for i in range(14, 45):
        sumdata += dats[i]
    dats[14] = ~sumdata & 0x00FF

    sumdata1 = 0x00
    for i in range(2, 45):
        sumdata1 += dats[i]
    dats[13] = ~sumdata1 & 0x00FF

    hex_dats = [f"0x{num:02X}" for num in dats]  # 批量转换成16进制0x00
    str_data = ','.join(hex_dats)

    agv_realdata.data = str_data
    await agv_realdata.save()
